home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / telecom / 46 / pascal / strval.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1986-08-15  |  6.6 KB  |  302 lines

  1. {***
  2.  *   Floating Point Conversion routines.
  3.  *   From Real to String and String to Real
  4.  *
  5.  *   By Kevin L. McGrath
  6.  ***}
  7.  
  8. PROCEDURE Str(Value: Real; VAR St: String);
  9.  
  10. {* Notes:
  11.  *   This routine is only accurate up to 9 digits becuase of the LongTrunc.
  12.  *   It HAD rounding errors, but they are now fixed (with the LongTrunc)
  13.  *
  14.  * O.S.S. Pascals Floating Point Format:
  15.  *   This is just a guess, but here goes...
  16.  *   One byte of exponent biased by 128 to give a +38 to -38 range.
  17.  *   Fourty bits of mantissa to give 11 digits of accuracy, One bit sign.
  18.  *   Most floating points are normalized to the left, with the point between
  19.  *   the most significant bit of the mantissa and the second most, so I think
  20.  *   this is two.  To find out, just plug out a routine that has a pointer
  21.  *   to a real, coerce's it into a pointer to a record structure of byte like
  22.  *   this:
  23.  *     Record
  24.  *       Exponent:      Byte;
  25.  *       MantissaOne:   Long;
  26.  *       MantissaTwo:   Long;
  27.  *       MantissaThree: Long;
  28.  *     End;
  29.  *   then you can extract the exponent and mantissa just by doing a
  30.  *   "Ptr.Exponent" or somethin like that.  Well, I haven't had time to get
  31.  *   that fancy with this, but I have used this routine and am sure it works.
  32.  *   Hope you guys at O.S.S. can vert it to some kind of normal ASM function!
  33.  *      Good Luck...   (Nice Compiler)
  34.  *      Call me if there are any probs, dig?
  35.  *}
  36.  
  37.  
  38. Const
  39.   Max_Digits    = 09;
  40.   Max_Exponent  = 38;
  41.  
  42. Var
  43.   Val:          Real;
  44.   TempInt,
  45.   Sig_Digits,
  46.   Dec_Exp,
  47.   I:            Integer;
  48.   Digits:       String;
  49.  
  50. Begin
  51.   Val := Abs(Value);
  52.   Dec_Exp := 0;
  53.  
  54.   {* Get the exponent without Natural Log (Ln doesn't seem to work fer me) *}
  55.  
  56.   If (Val < 1) And (Val > 0) Then
  57.   Begin
  58.     For I := 0 To (Max_Exponent-1) Do
  59.       If (Val < (1/PwrOfTen(I))) And (Val >= (1/PwrOfTen(I+1))) Then
  60.         Dec_Exp := -(I+1);
  61.     Val := Val * PwrOfTen(Abs(Dec_Exp)-1);
  62.   End
  63.   Else
  64.   Begin
  65.     For I := 0 To (Max_Exponent-1) Do
  66.       If (Val >= PwrOfTen(I)) And (Val < PwrOfTen(I+1)) Then
  67.         Dec_Exp := I;
  68.     Val := Val / PwrOfTen(Dec_Exp+1);
  69.   End;
  70.  
  71. { Get decimal digits by stripping }
  72.  
  73.   Digits := '';
  74.   St := '';
  75.  
  76.   For I := Max_Digits DownTo 1 Do
  77.   Begin
  78.     { Take care of rounding problems }
  79.  
  80.     Val := Long_Trunc(Val*PwrOfTen(I)+0.5)/PwrOfTen(I);
  81.  
  82.     Val := Val*10.0;
  83.     Digits := ConCat(Digits,Chr(48+Trunc(Val)));
  84.     Val := Val-Trunc(Val);
  85.  
  86.     { Take care of rounding problems }
  87.  
  88.     Val := Long_Trunc(Val*PwrOfTen(I)+0.5)/PwrOfTen(I);
  89.  
  90.   End;
  91.  
  92. { Format and put result in St }
  93. { Put sign }
  94.  
  95.   If Value < 0 Then St := '-';
  96.  
  97. { Compute significant digits }
  98.  
  99.   Sig_Digits := Max_Digits;
  100.   I := Max_Digits - 1;
  101.   While ((Digits[I]='0') And (I>0)) Do
  102.   Begin
  103.     Sig_Digits := Sig_Digits - 1;
  104.     I := I - 1;
  105.   End;
  106.   Sig_Digits := Sig_Digits - 1;
  107.  
  108. { Put in exponential or non-exonential }
  109.  
  110.   If ((Sig_Digits-Max_Digits)<=Dec_Exp) And (Dec_Exp<=Max_Digits) Then
  111.   Begin
  112.     { Non-exponental form }
  113.     { Put decimal point and leading zeros for numbers with negative exponents }
  114.  
  115.     If Dec_Exp < 0 Then
  116.     Begin
  117.       St := ConCat(St,'.');
  118.       For I := 1 To -Dec_Exp-1 Do
  119.         St := ConCat(St,'0');
  120.     End;
  121.  
  122.     { Put significant digits }
  123.  
  124.     St := ConCat(St,Digits[1]);
  125.     For I := 1 To Sig_Digits-1 Do
  126.     Begin
  127.       If Dec_Exp = 0 Then
  128.         St := ConCat(St,'.');
  129.       St := ConCat(St,Digits[I+1]);
  130.       Dec_Exp := Dec_Exp - 1;
  131.     End;
  132.  
  133.     { Put trailing zeros }
  134.  
  135.     While Dec_Exp > 0 Do
  136.     Begin
  137.       St := ConCat(St,'0');
  138.       Dec_Exp := Dec_Exp - 1;
  139.     End;
  140.   End
  141.   Else
  142.   Begin
  143.     { Exponental form }
  144.     { Put first digit }
  145.  
  146.     St := ConCat(St,Digits[1]);
  147.  
  148.     { Put decimal point }
  149.  
  150.     If Sig_Digits > 1 Then
  151.       St := ConCat(St,'.');
  152.  
  153.     { Put remaining significant digits }
  154.  
  155.     For I := 1 To (Sig_Digits - 1) Do
  156.       St := ConCat(St,Digits[I+1]);
  157.  
  158.     { Put the 'E' for the exponent }
  159.  
  160.     St := ConCat(St,'E');
  161.  
  162.     { Put exponents sign }
  163.  
  164.     If Dec_Exp >= 0 Then
  165.       St := ConCat(St,'+')
  166.     Else
  167.     Begin
  168.       St := ConCat(St,'-');
  169.       Dec_Exp := Abs(Dec_Exp);
  170.     End;
  171.  
  172.     { Put the exponent }
  173.  
  174.     If Dec_Exp >= 10 Then
  175.     Begin
  176.       St := ConCat(St,Chr(48+(Dec_Exp Div 10)));
  177.       St := ConCat(St,Chr(48+Dec_Exp-((Dec_Exp Div 10) * 10)));
  178.     End
  179.     Else
  180.     Begin
  181.       St := ConCat(St,'0');
  182.       St := ConCat(St,Chr(48+Dec_Exp));
  183.     End;
  184.   End;
  185. End;
  186.  
  187.  
  188. FUNCTION Val( St: String): Real;
  189.  
  190. Const
  191.   Max_Digits    = 09;
  192.  
  193. Var
  194.   Dec_Exp,
  195.   Exp_Value,
  196.   Count,
  197.   Position:     Integer;
  198.   Chr:          Char;
  199.   Result:       Real;
  200.   Dec_Sign,
  201.   Exp_Sign:     Boolean;
  202.  
  203.   PROCEDURE Add_Digit;
  204.  
  205.   Begin
  206.     Result := (Result * 10) + (Ord(Chr) & $0F);
  207.   End;
  208.  
  209.   PROCEDURE Read_Chr;
  210.  
  211.   Begin
  212.     Position := Position + 1;
  213.     If Position > Length(St) Then
  214.       Chr := 'X'
  215.     Else
  216.       Chr := St[Position];
  217.   End;
  218.  
  219. Begin
  220.   Position := 0;
  221.   Read_Chr;
  222.   Result := 0.0;
  223.  
  224. { Get sign }
  225.  
  226.   Dec_Sign := False;
  227.   If Chr = '+' Then Read_Chr;
  228.   If Chr = '-' Then
  229.   Begin
  230.     Read_Chr;
  231.     Dec_Sign := True;
  232.   End;
  233.  
  234. { Get digits to left of decimal point }
  235.  
  236.   Dec_Exp := 0;
  237.   Count := Max_Digits;
  238.   While ('0' <= Chr) And (Chr <= '9') Do
  239.   Begin
  240.     If Count > 0 Then
  241.     Begin
  242.       Add_Digit;
  243.       Count := Count - 1;
  244.     End
  245.     Else
  246.       Dec_Exp := Dec_Exp + 1;
  247.     Read_Chr;
  248.   End;
  249.  
  250. { Get digits to the right of decimal point }
  251.  
  252.   If Chr = '.' Then
  253.   Begin
  254.     Read_Chr;
  255.     While ('0' <= Chr) And (Chr <= '9') Do
  256.     Begin
  257.       If Count > 0 Then
  258.       Begin
  259.         Add_Digit;
  260.         Dec_Exp := Dec_Exp - 1;
  261.         Count := Count - 1;
  262.       End;
  263.       Read_Chr;
  264.     End;
  265.   End;
  266.  
  267. { Get exponent part }
  268.  
  269.   If (Chr = 'E') Or (Chr = 'e') Then
  270.   Begin
  271.     Read_Chr;
  272.     Exp_Sign := False;
  273.     If Chr = '+' Then Read_Chr;
  274.     If Chr = '-' Then
  275.     Begin
  276.       Read_Chr;
  277.       Exp_Sign := True;
  278.     End;
  279.     Exp_Value := 0;
  280.     If ('0'<=Chr) And (Chr<='9') Then Exp_Value := (Ord(Chr) & $0F)*10;
  281.     Read_Chr;
  282.     If ('0'<=Chr) And (Chr<='9') Then Exp_Value := Exp_Value+(Ord(Chr) & $0F);
  283.     If (Chr = 'X') And (Exp_Value >= 10) Then Exp_Value := Exp_Value Div 10;
  284.     If Exp_Sign Then
  285.       Dec_Exp := Dec_Exp - Exp_Value
  286.     Else
  287.       Dec_Exp := Dec_Exp + Exp_Value;
  288.   End;
  289.  
  290. { Multiply or divide Result by power of 10 specified by Dec_Exp }
  291.  
  292.   If Dec_Exp > 0 Then
  293.     Result := Result * PwrOfTen(Dec_Exp)
  294.   Else
  295.     Result := Result / PwrOfTen(Abs(Dec_Exp));
  296.  
  297.   If Dec_Sign Then Result := -Result;
  298.  
  299.   Val := Result;
  300.  
  301. End;
  302.